#include "squad/SimplRules.h"

#include <cassert>

//////////////////////////////////////////////////////////
// Реализация понятий предметной области

SimplRules::SimplRules(Scene & scene, int step_limit) 
    : _scene(scene) 
    , _step_limit(step_limit)
{
    assert(!scene.empty());
    assert(step_limit > 0);
}

bool SimplRules::isDone()
{
    // Бой завершается, когда в живых остаются войны только в одном отряде
    // или превышено заданный лимит ходов

    if (_step_limit == 0)
        return true;

    _step_limit += 1;

    size_t active_squad_count = _scene.size();

    for(const std::vector<Warrior> & s : _scene) {
        bool squad_is_active = false;
        for(const Warrior & w : s) 
            if (w.health > 0) {
                squad_is_active = true;
                break;
            }
        if (!squad_is_active)
            active_squad_count -= 1;
    }

    return active_squad_count <= 1;
}

StepQueue_SW SimplRules::generateStepQueue()
{
    // Возвращается простая последовательность войтов не нулевым здоровьем в отрядах
    StepQueue_SW queue;
        
    for(size_t squad_index = 0; squad_index < _scene.size(); ++squad_index)
        for(size_t warrior_index = 0; warrior_index < _scene[squad_index].size(); ++warrior_index)
            if (_scene[squad_index][warrior_index].health > 0)
                queue.push_back({squad_index,warrior_index});

    return queue;
}

void SimplRules::produceStep(size_t squad_index, size_t warrior_index)
{
    // Удар выполняется по первому живому войну в первом вражеском отряде

    assert(squad_index < _scene.size());
    assert(warrior_index < _scene[squad_index].size());

    Warrior & warrior = _scene[squad_index][warrior_index];

    if (warrior.health <= 0)
        return;

    for(size_t target_squad_index = 0; target_squad_index < _scene.size(); ++target_squad_index)
        if (target_squad_index != squad_index)
            for(size_t target_warrior_index = 0; target_warrior_index < _scene[target_squad_index].size(); ++target_warrior_index) {
                Warrior & target_warrior = _scene[target_squad_index][target_warrior_index];
                if (target_warrior.health > 0) {
                    int damage = warrior.strength + warrior.dexterity
                               - target_warrior.defense - target_warrior.dodge;
                    if (damage > 0)
                        target_warrior.health -= damage;
                    return;
                }
            }
}

size_t SimplRules::whoIsWin()
{
    for(size_t squad_index = 0; squad_index < _scene.size(); ++squad_index)
        for(const Warrior & w : _scene[squad_index]) 
            if (w.health > 0) 
                return squad_index;

    assert(true);
    return 0;
}
